home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************}
- { StandardGetFolder.c }
- { }
- { This little chunk o' code implements a way to let the user choose a }
- { folder to save files in via a StandardFile Dialog. }
- { }
- { Since the code uses the CustomGetFile function and depends on the use of }
- { FSSpec records, it only works under System 7.0 or later. }
- { }
- { And don't forget to include the custom dialog resources ( a 'DITL' and }
- { 'DLOG') in your project. }
- { }
- { Portions of this code were originally provided by Paul Forrester }
- { (paulf@apple.com) to the think-c internet mailing list in response to my }
- { my question on how to do exactly what this code does. I've added a }
- { couple of features, such as the ability to handle aliased folders and }
- { the programmer definable prompt. I also cleaned and tightened the code, }
- { stomped a couple of bugs, and packaged it up neatly. Bunches of work, }
- { but I learned A LOT about Standard File, the File Manager, the Dialog }
- { Manager, and the Alias Manager. I tried to include in the comments some }
- { of the neat stuff I discovered in my hours of pouring over Inside Mac. }
- { Hope you find it educational as well as useful. }
- {******************************************************************************}
- { Converted to Pascal by Peter N Lewis <peter.lewis@info.curtin.edu.au> Dec 1992 }
-
- And back to C again (I didn't have the original C code and I didn't want to replace this with
- work from another StandardGetFolder library. dhn.
- */
-
- #include <Aliases.h>
- #include <Script.h>
- #include <TextUtils.h>
- #include <Types.h>
- #include <StandardFile.h>
- #include <LowMem.h>
-
- #include "IC Misc Subs.h"
- #include "StandardGetFolder.h"
- #include "IC StandardFile.h"
-
- // Global Variables
- Str255 gCurrentSelectedFolder;
-
- // { The following set of routines are used to access a couple of low memory }
- // { globals that are necessary when extending Standard File. One example is }
- // { trying to get the current directory while in a file filter. These routines }
- // { were used to bottleneck all the low memory usage. If the system one day }
- // { supports them with a trap call, then we can easily update these routines. }
-
- void GetSFLocation(short* vrn,long* dirID){
- *vrn=-LMGetSFSaveDisk();
- *dirID=LMGetCurDirStore();
- }
-
- void SetSFLocation(short vrn,long dirID){
- LMSetSFSaveDisk(-vrn);
- LMSetCurDirStore(dirID);
- }
-
- // {******************************************************************************}
- // { MyCustomGetDirectoryFileFilter }
- // { }
- // { This is the file filter passed to CustomGetFile. It passes folders only. }
- // {******************************************************************************}
- pascal Boolean MyCustomGetDirectoryFileFilter(CInfoPBRec* myPB,Ptr myDataPtr){
- Boolean dir,invis=false;
-
- dir=(myPB->hFileInfo.ioFlAttrib&16);
- if (dir)
- invis=(myPB->dirInfo.ioDrUsrWds.frFlags&0x4000);
-
- // return true to suppress, false to show
-
- return !((dir)&&(!(invis)));
- }
-
-
- // {******************************************************************************}
- // { MyCustomGetDirectoryDlogHook }
- // { }
- // { This function lets us process item hits in the GetFolderDialog. We're }
- // { only interested if the user hit the selectFolder button. We pass all }
- // { other item hits back to ModalDialog. }
- // {******************************************************************************}
-
- void SetButtonTitle(DialogPtr theDialog,StringPtr name){
- short resultCode;
- short width;
- Str255 TmpStr,left,right,bname;
- short itemType;
- Handle itemHandle;
- Rect itemRect;
- short p;
-
- // only if the names are not the same
- if (IUEqualString(gCurrentSelectedFolder,name)){
- GetDialogItem(theDialog,rGetFolderSelectString,&itemType,&itemHandle,&itemRect);
- GetDialogItemText(itemHandle,TmpStr);
-
- p=TPPos("\p^1",TmpStr);
-
- // p points at the ^1
- TPCopy(left,TmpStr,1,p-1);
- TPCopy(right,TmpStr,p+2,255);
-
- GetDialogItem(theDialog,rGetFolderButton,&itemType,&itemHandle,&itemRect);
-
- SetPString(gCurrentSelectedFolder,1,name);
-
- // {*-------------------------------------------------------------------------}
- // { Find the width left over in the button after drawing the word 'Select' }
- // { the quotation marks. Truncate the new name to this length. }
- // {-------------------------------------------------------------------------*}
-
- SetPString(bname,4,"\p ",left,right,"\p ");
-
- width=(itemRect.right-itemRect.left)-StringWidth(bname);
- resultCode=TruncString(width,name,smTruncEnd);
-
- // add the name to the temp str
- SetPString(TmpStr,3,left,name,right);
-
- SetControlTitle((ControlHandle)itemHandle,TmpStr);
- ValidRect(&itemRect);
- }
- }
-
- void SetFolderButtonTitle(DialogPtr dlg,short vrn,long dirID){
- Str63 name;
- CInfoPBRec pb;
- OSErr oe;
-
- pb.hFileInfo.ioNamePtr=name;
- pb.hFileInfo.ioVRefNum=vrn;
- pb.hFileInfo.ioDirID=dirID;
- pb.hFileInfo.ioFDirIndex=-1;
-
- if (PBGetCatInfoSync(&pb)==noErr)
- SetButtonTitle(dlg,name);
- }
-
- pascal short MyCustomGetDirectoryDlogHook(short item,DialogPtr theDialog,Ptr myDataPtr){
- short itemType;
- Rect itemRect;
- Handle itemHandle;
- StandardFileReplyPtr mySFRPtr;
-
- // {*-------------------------------------------------------------------------}
- // { CustomGet calls dialog hook for both main and subsidiary dialog boxes. }
- // { Make sure that dialog record indicates that this is the main GetFolder }
- // { dialog. }
- // {-------------------------------------------------------------------------*}
-
- if (((OSType)((WindowPeek)theDialog)->refCon)==sfMainDialogRefCon){
- mySFRPtr=(StandardFileReplyPtr)myDataPtr;
-
- if (item==sfHookFirstCall){
- // {*-----------------------------------------------------------------}
- // { Set the prompt displayed above the file list... }
- // {-----------------------------------------------------------------*}
- GetDialogItem(theDialog,rGetFolderMessage,&itemType,&itemHandle,&itemRect);
- SetDialogItemText(itemHandle,gCurrentSelectedFolder);
- gCurrentSelectedFolder[0]=0;
- } else {
- if (mySFRPtr->sfFile.name[0]==0){
- GetSFLocation(&(mySFRPtr->sfFile.vRefNum),&(mySFRPtr->sfFile.parID));
- mySFRPtr->sfFile.name[0]=0;
- SetFolderButtonTitle(theDialog,mySFRPtr->sfFile.vRefNum,mySFRPtr->sfFile.parID);
- } else {
- SetButtonTitle(theDialog,mySFRPtr->sfFile.name);
- }
- }
-
- if (item==rGetFolderButton){
- item=sfItemCancelButton;
- mySFRPtr->sfGood=true;
- }
- }
- return item;
- }
-
- // {******************************************************************************}
- // { StandardGetFolder }
- // { }
- // { The StandardGetFolder function. You pass it the point where you want the }
- // { standard file dialog box drawn, the prompt to display above the file }
- // { list, and a pointer to an StandardFileReply record. }
- // { }
- // { Upon return, the sfFile field of the SFReply record contains the volume }
- // { reference number and directory ID that specify the folder the user }
- // { chose. It also passes back the name of the chosen folder. The sfGood }
- // { field is set to true if the user chose a folder, or false if not. }
- // {******************************************************************************}
-
- void StandardGetFolder(Point where,StringPtr message,StandardFileReply* mySFReply){
- SFTypeList theTypeList;
- CInfoPBRec pb;
- Boolean isfolder,wasaliased;
- OSErr oe;
-
- // {*-------------------------------------------------------------------------}
- // { Copy the prompt to be displayed above the file list into gCurrentSelectedFolder }
- // { When MyCustomGetDirectoryDlogHook is called for }
- // { the first time, it will use this info to draw the prompt. }
- // {-------------------------------------------------------------------------*}
- SetPString(gCurrentSelectedFolder,1,message);
-
- // {*-------------------------------------------------------------------------}
- // { Call CustomGetFile. Pass it a pointer to the file filter and dialog }
- // { hook functions. Also pass a pointer to mySFReply in the user data field. }
- // {-------------------------------------------------------------------------*}
-
- CustomGetFile(gMyCustomGetDirectoryFileFilter,-1,theTypeList,mySFReply,rGetFolderDialog,
- where,gMyCustomGetDirectoryDlogHook,
- (ModalFilterYDUPP)0,(short*)0,(ActivateYDUPP)0,(void*)mySFReply);
-
- // {*-------------------------------------------------------------------------}
- // { Ok, now the reply record contains the volume reference number and the }
- // { name of the selected folder. We need to use PBGetCatInfo to get the }
- // { directory ID of the selected folder. }
- // {-------------------------------------------------------------------------*}
- if (mySFReply->sfGood){ //{ Don't call PBGetCatInfo on cancel! }
-
- if (mySFReply->sfFile.name[0]!=0){
- oe=ResolveAliasFile(&(mySFReply->sfFile), true,&isfolder,&wasaliased);
- if ((oe==noErr)&&(!isfolder)){
- // not a folder, weird error here
- }
- if (oe==noErr){
- pb.hFileInfo.ioVRefNum=mySFReply->sfFile.vRefNum;
- pb.hFileInfo.ioDirID=mySFReply->sfFile.parID;
- pb.hFileInfo.ioNamePtr=mySFReply->sfFile.name;
- pb.hFileInfo.ioFDirIndex=0;
-
- oe=PBGetCatInfoSync(&pb);
- }
-
- mySFReply->sfGood=(oe==noErr);
- mySFReply->sfFile.parID=pb.dirInfo.ioDrDirID;
- mySFReply->sfFile.name[0]=0;
- }
-
- if (oe==noErr){
- pb.hFileInfo.ioVRefNum=mySFReply->sfFile.vRefNum;
- pb.hFileInfo.ioDirID=mySFReply->sfFile.parID;
- pb.hFileInfo.ioNamePtr=mySFReply->sfFile.name;
- pb.hFileInfo.ioFDirIndex=-1;
-
- oe=PBGetCatInfoSync(&pb);
- }
- }
- }
-
-